import socket
import threading
import crcmod
import select

BOARD_HOST='127.0.0.1'  #板卡IP
BOARD_PORT=8809             #板卡端口号

PC_HOST = '127.0.0.1'       #Telnet IP
PC_PORT = 8808              #Telnet 端口号

BOARD_ID = 0x01             #板卡A类协议IP

def crc16Add(read):
    crc16 = crcmod.mkCrcFun(0x18005, rev=True, initCrc=0xFFFF, xorOut=0x0000)
    readcrcout = crc16(read)
    return readcrcout

class Queue(object):# 定义队列类
    def __init__(self,size):
       self.size = size #定义队列长度
       self.queue = []#存储队列 列表
    #返回对象的字符串表达式 方便调试
    def __str__(self):
        return str(self.queue)#什么含义

    #删除某元素
    def delete(self, n):
        for i in range(n):
           self.queue.pop(0)
                      
    #插入某元素
    def inPut(self,n,m):#n代表列表当前的第n位元素 m代表传入的值
        for i in range(n):
           self.queue.append(m[i])
           
    #获取元素
    def outPut(self):#n代表列表当前的第n位元素 m代表传入的值
        return self.queue.copy()
                           
    #获取当前长度
    def getSize(self):
        return len(self.queue)
    #判空
    def isEmpty(self):
        if len(self.queue)==0:
            return True
        return False
    #判满
    def isFull(self):
        if len(self.queue) == self.size:
            return True
        return False

queueTest = Queue(0x4000)

clent=socket.socket(socket.AF_INET,socket.SOCK_STREAM)      #定义socket类型，网络通信，TCP
clent.connect((BOARD_HOST,BOARD_PORT))                      #要连接的IP与端口
print("板卡的ip地址和端口号:", BOARD_HOST,BOARD_PORT)

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server.bind((PC_HOST, PC_PORT))     # 套接字绑定的IP与端口
server.listen(10)                   # 开始TCP监听
inputs = [server]                   # 存放需要被检测可读的socket
outputs = []                        # 存放需要被检测可写的socket

def server_PC():
    while inputs:
        readable, writable, exceptional = select.select(inputs, outputs, inputs)
        # 可读
        for RRR in readable:
            if RRR is server:     # 可读的是server,说明有连接进入
                connection, client_address = RRR.accept()
                print("PC的ip地址和端口号:", client_address)
                telnetcmd = [0xff, 0xfb, 0x01, 0xff, 0xfb, 0x03, 0xff, 0xfc, 0x1f]
                connection.send(bytes(telnetcmd))
                inputs.append(connection)
            else:
                recv_data = RRR.recv(0x1000)
                if recv_data:
                    # Telnet需对特殊帧进行处理
                    if (len(recv_data) > 1):
                        if (recv_data[0] == 0xff) & (recv_data[1] != 0xff):
                            continue
                    list_rx = list(recv_data)
                    for i in range(len(recv_data)):
                        if (list_rx[i] == 0xFF) & ((i + 1) < len(list_rx)):
                            if list_rx[i + 1] == 0xFF:
                                list_rx.pop(i + 1)
                        if (list_rx[i] == 0x0D) & ((i + 1) < len(list_rx)):
                            if list_rx[i + 1] == 0x00:
                                list_rx.pop(i + 1)
                        if ((i + 1) >= len(list_rx)):
                            break
                        
                    arr = [0xA3,0x00,0x00,0x00,BOARD_ID,0x53,0x00,0x10, 0x11]
                    arr[2] = len(list_rx) + 8
                    arr.extend(list_rx)
                    arr.append(0x0D)
                    arr.append(0x0A)
                    clent.send(bytes(arr))
                    print("pc len ==>>{}".format(len(list_rx)))
                    print("data ==>>{}".format(bytes(list_rx).hex().upper()))
                    print("PC SEND ==>>" + bytes(arr).hex())
                else:
                    # 收到为空的数据,意味着对方已经断开连接,需要做清理工作
                    if RRR in outputs:
                        outputs.remove(RRR)
                    inputs.remove(RRR)
                    RRR.close()
        # 可写
        for w in writable:
            outputs.remove(w)

        # 异常
        for SSS in exceptional:
            inputs.remove(SSS)
            if SSS in outputs:
                outputs.remove(SSS)
            SSS.close()  

def clent_BOARD():
        while True:
                rx_string=clent.recv(0x1000)
                rx_len = len(rx_string)
                if (rx_len == 0):
                    clent.connect((BOARD_HOST,BOARD_PORT))                      #要连接的IP与端口
                queueTest.inPut(rx_len, rx_string)
                rx_len = queueTest.getSize()
                rx_string = queueTest.outPut()
                rx_index = 0
                while rx_len > rx_index:
                        if rx_string[rx_index] == 0xA3:
                                if rx_index + 2 >= rx_len:
                                    break
                                framlen = (rx_string[rx_index + 1 ]<< 8) + rx_string[rx_index + 2]
                                if (rx_index + framlen > rx_len):
                                    break
                                if (rx_index + framlen + 2 >= rx_len):
                                    break
                                if (rx_string[rx_index + framlen + 1] == 0x0D) & (rx_string[rx_index + framlen + 2] == 0x0A):
                                        if ((rx_string[rx_index + 6] == 0x00) & (rx_string[rx_index + 7] == 0x10)):
                                                # print("BOARD SEND ==>>" + bytes(rx_string[rx_index + 8 : rx_index + framlen + 1]).hex().upper())
                                                b_list = list(bytes(rx_string[rx_index + 9 : rx_index + framlen + 1]))
                                                if len(b_list) != 0:
                                                    i = 0
                                                    while 1:
                                                        if (b_list[i] == 0xFF):
                                                            b_list.insert(i, 0xFF)
                                                            i = i + 1
                                                        if b_list[i] == 0x0D:
                                                            if (i + 1) < len(b_list):
                                                                if (b_list[i + 1] != 0x00) & (b_list[i + 1] != 0x0A):
                                                                    b_list.insert(i + 1, 0x00)
                                                                    i = i + 1
                                                            else:
                                                                b_list.insert(i + 1, 0x00)
                                                                i = i + 1
                                                        i = i + 1
                                                        if (i >= len(b_list)):
                                                            break
                                                    for TTT in inputs:
                                                        if (TTT != server):
                                                            print("BOARD len ==>>{}".format(len(b_list)))
                                                            print("BOARD data ==>>{}".format(bytes(b_list).hex().upper()))
                                                            TTT.send(bytes(b_list))
                                                rx_index = rx_index + framlen + 3
                                                continue
                        elif rx_string[rx_index] == 0xA0:
                                framlen = rx_string[rx_index + 1 ]
                                CRC_value = crc16Add(bytes(rx_string[rx_index : rx_index + framlen]))
                                if rx_index + framlen + 1 > rx_len:
                                        break                                
                                if (rx_string[rx_index + framlen + 1] == CRC_value >> 8) & (rx_string[rx_index + framlen] == CRC_value & 0xff):
                                        rx_index = rx_index + framlen + 2
                                        continue                                        
                        rx_index = rx_index + 1
                queueTest.delete(rx_index - 1)
                           
# 创建新线程
thread1 = threading.Thread(target=clent_BOARD)
thread2 = threading.Thread(target=server_PC)
threads = []
# 开启新线程
thread1.start()
thread2.start()

# 添加线程到线程列表
threads.append(thread1)
threads.append(thread2)

# 等待所有线程完成
for t in threads:
    t.join()
print ("退出主线程")        
clent.close()   #关闭连接
server.close()